#ifndef __WED_PHY_H__
#define __WED_PHY_H__
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "Wed_framework_config.h"
#include "dev/Wed_dev.h"
#include "mem/Wed_mem.h"
#include "kernel/Wed_clock.h"
#include "dev/gpio/Wed_gpio.h"

/* \brief PHY 控制寄存器 */
#define GEN_PHY_CTRL_REG             0
/* \brief PHY ID 1 寄存器 */
#define GEN_PHY_ID1_REG              2
/* \brief PHY ID 2 寄存器 */
#define GEN_PHY_ID2_REG              3

#define GEN_PHY_ANAR_REG             4      /** \brief Auto-Negotiation advertisement register*/

#define GEN_PHY_ANAR_10TX_HD            0x0020
#define GEN_PHY_ANAR_10TX_FD            0x0040
#define GEN_PHY_ANAR_100TX_HD           0x0080
#define GEN_PHY_ANAR_100TX_FD           0x0100

#define DISABLE_100M_10M_ABILITY    (GEN_PHY_ANAR_10TX_HD  | GEN_PHY_ANAR_10TX_FD | \
                                     GEN_PHY_ANAR_100TX_HD | GEN_PHY_ANAR_100TX_FD)

#define GEN_PHY_CR_SPEEDMSB             (0x1U << 6)
#define GEN_PHY_CR_FULL_DUPLEX          (0x1U << 8)
#define GEN_PHY_CR_AUTO_NEGO_RESTART    (0x1U << 9)
#define GEN_PHY_CR_PWR_DOWN             (0x1U << 11)
#define GEN_PHY_CR_AUTO_NEGO            (0x1U << 12)
#define GEN_PHY_CR_SPEEDLSB             (0x1U << 13)
#define GEN_PHY_CR_LOOPBACK             (0x1U << 14)
#define GEN_PHY_CR_RESET                (0x1U << 15)

/* \brief MII 设备操作函数集结构体 */
struct Wed_mii_opts {
    int (*p_fn_mdio_write)(void *p_opts_arg, int phy_addr, int phy_reg, uint16_t data);
    int (*p_fn_mdio_read)(void *p_opts_arg, int phy_addr, int phy_reg, uint16_t *p_data);
};

struct Wed_phy_cfg {

};

/* \brief PHY 设备结构体 */
struct Wed_phy {
    struct Wed_dev        dev;            /* 基础设备 */
    struct Wed_list_node  node;           /* 网络设备节点 */
    struct Wed_mii_opts  *p_opts;         /* 操作函数集 */
    void                 *p_opts_arg;     /* 操作函数参数 */
    struct Wed_mutex      lock;           /* 互斥锁 */
    char                 *p_reset_name;   /* 复位引脚名称 */
    int                   is_link_up;     /* 是否链接 */
    int                   is_full_duplex; /* 是否是全双工 */
    int                   speed_mps;      /* 速度 */
};

/**
 * \brief PHY 设备链表初始化
 *
 * @return 成功返回 0
 */
int Wed_phy_list_init(void);
/**
 * \brief PHY 设备注册函数
 *
 * @param p_phy_name   PHY 设备名字
 * @param p_opts       MII 操作函数集
 * @param p_opts_arg   操作函数参数
 * @param p_reset_name 复位引脚名称
 *
 * @return 成功返回 0
 */
int Wed_phy_register(char                *p_phy_name,
                     struct Wed_mii_opts *p_opts,
                     void                *p_opts_arg,
                     char                *p_reset_name);
/**
 * \brief 根据名字获取 PHY 设备结构体
 *
 * @param p_gpio_name PHY 名字
 *
 * @return 找到返回 PHY 设备结构体，没找到返回 NULL
 */
struct Wed_phy *Wed_phy_find_by_name(char *p_phy_name);
/**
 * \brief PHY 设备复位
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 * @param time_out 超时时间（毫秒）
 *
 * @return 成功返回 0
 */
int Wed_phy_reset(struct Wed_phy *p_phy, int phy_addr, uint32_t time_out);
/**
 * \brief PHY 设备下电
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 *
 * @return 成功返回 0
 */
int Wed_phy_down(struct Wed_phy *p_phy, int phy_addr);
/**
 * \brief PHY 设备上电
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 *
 * @return 成功返回 0
 */
int Wed_phy_up(struct Wed_phy *p_phy, int phy_addr);
/**
 * \brief PHY 设备工作模式设置
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 * @param p_cfg    配置结构体
 *
 * @return 成功返回 0
 */
int Wed_phy_work_model_set(struct Wed_phy     *p_phy,
                           int                 phy_addr,
                           struct Wed_phy_cfg *p_cfg);
#endif
